#include "action_manager.h"
#include "../../logger.h"

namespace jlib {


void ActionManager::start (Action *action) {
  debug_assert(action);
  if (this->_updating) {
    this->_startCache.emplace_back(action);
    return;
  }
  auto &list = this->_buckets[action->target];
  list.emplace_back(action);
  action->start();
}


void ActionManager::stop (Action *action) {
  debug_assert(action);
  auto iter = this->_buckets.find(action->target);
  if (iter == this->_buckets.end())
    return;
  for (auto &ptr : iter->second) {
    if (ptr == action) {
      ptr = nullptr;
      return;
    }
  }
}


void ActionManager::stop (Object *target) {
  auto iter = this->_buckets.find(target);
  if (iter == this->_buckets.end())
    return;
  for (auto &ptr : iter->second)
    ptr = nullptr;
}


void ActionManager::stopAll () {
  for (auto &iter : this->_buckets)
    for (auto &ptr : iter.second)
      ptr = nullptr;
}


void ActionManager::update (float dt) {

  this->_updating = true;
  for (auto &pair : this->_buckets) {
    for (auto &action : pair.second) {
      if (!action)
        continue;
      action->update(dt);
      if (action->completed() && action->onCompleted)
        action->onCompleted();
    }
  }
  this->_updating = false;

  for (auto iter = this->_buckets.begin(), end = this->_buckets.end(); iter != end; ) {
    auto &list = iter->second;
    auto e = list.size();
    auto i = 0UL;
    for (; i < e && list[i] != nullptr; ++i);
    if (i >= e)
      continue;
    auto j = i + 1;
    for (; j < e && list[j] == nullptr; ++j);
    while (j < e) {
      auto &src = list[j++];
      if (!src)
        continue;
      list[i++] = std::move(src);
    }
    if (i > 0) {
      list.resize(i);
      ++iter;
    }
    else this->_buckets.erase(iter++);
  }

  for (auto &action : this->_startCache) {
    auto &list = this->_buckets[action->target];
    list.emplace_back(action);
    action->start();
  }
  this->_startCache.clear();
}


void ActionManager::clear () {
  this->_buckets.clear();
  this->_startCache.clear();
}


} // namespace jlib